package com.example.activiti.service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import org.activiti.bpmn.model.UserTask;
import org.activiti.engine.HistoryService;
import org.activiti.engine.IdentityService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.identity.User;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.alibaba.fastjson.JSONObject;
import com.example.activiti.common.ActiveNoticeInfo;
import com.example.activiti.common.constant.InstanceStatus;
import com.example.activiti.common.constant.PublicKeyword;
import com.example.activiti.dto.ComplateActivitiApplyDto;
import com.example.activiti.dto.publicDto.ActivitiRequestDto;
import com.example.activiti.dto.publicDto.ActivitiResponseDto;

@Service
public class ComplateActivitiService {
	//对activiti资源进行操作，比如部署文件，附件
	@Resource
    private RepositoryService repositoryService;
	//运行时服务，可以对运行时流程进行修改，如增加变量，移除变量等
    @Resource
    private RuntimeService runtimeService;
    //对用户任务进行操作和查询
    @Resource
    private TaskService taskService;
    //历史记录服务，对审批历史进行操作
    @Resource
    private HistoryService historyService;
    @Autowired
    private IdentityService identityService;
    
    @Autowired
    private ActivitiUserManageService userManage;
    @Resource
    private HttpServletRequest request;
    @Autowired
    private ActiveNoticeInfo activeNoticeInfo;
	
	/**
     * complateQingjia
          * 发布流程（发起流程）
     * @param paramMap 是左右的参数
     */
    public List<ActivitiResponseDto> runtimeRelease(ActivitiRequestDto<ComplateActivitiApplyDto> activitiRequestDto){
    	//非常重要，设置起始人
        identityService.setAuthenticatedUserId(activitiRequestDto.getStartUser());
    	//获取流程名称调用启动流程
    	String processDefinitionKey = activitiRequestDto.getProcessesName();
    	
    	String jsonStr = JSONObject.toJSONString(activitiRequestDto.getReqeustBody());
        @SuppressWarnings("unchecked")
		Map<String, Object> map = JSONObject.parseObject(jsonStr, Map.class);
        //设置流程发起人（startUser是固定字段，都必须传的）
        map.put(PublicKeyword.STARTUSER, activitiRequestDto.getStartUser());
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processDefinitionKey, map);
        System.out.println("流程实例ID:"+processInstance.getId());
        System.out.println("流程定义ID:"+processInstance.getProcessDefinitionId());
        //设置流程变量，全局流程变量
        runtimeService.setVariable(processInstance.getId(), PublicKeyword.STARTPUBLICPARAM, map);
        //这是自定义的类
        ActivitiResponseDto activitiResponseDto = new ActivitiResponseDto();
        //设置流程实例id
        activitiResponseDto.setInstanceId(processInstance.getId());
        //流程定义Id
        activitiResponseDto.setProcessDefinitionId(processInstance.getProcessDefinitionId());
        //流程的名称
        activitiResponseDto.setProcessDefinitionName(processInstance.getProcessDefinitionKey());
        
        //流程启动并提交开始后默认将第一个自己提交的审批通过
        List<ActivitiResponseDto> activitResList = this.taskBeginQueryComplete(activitiRequestDto);
        
        return activitResList;
    }
    
    /**
          * 发布是查询任务并默认执行通过
     * @param username 这里的username是需要从数据库中查询出来的，如果为空则固定传jack，
     */
    public List<ActivitiResponseDto> taskBeginQueryComplete(ActivitiRequestDto<ComplateActivitiApplyDto> activitiRequestDto){
    	List<ActivitiResponseDto> resultList = new ArrayList<ActivitiResponseDto>();
    	String username = activitiRequestDto.getStartUser();
        // 模拟登录用户，获取到任务人,进行任务的查询和提交
        List<Task> list = taskService.createTaskQuery()
                .taskAssignee(username)
                .list();
        for (Task task : list) {
            System.out.println("--------------------------------------------");
            System.out.println("任务ID:" + task.getId());
            System.out.println("任务名称:" + task.getName());
            System.out.println("任务创建时间:" + task.getCreateTime());
            System.out.println("任务委派人:" + task.getAssignee());
            System.out.println("流程实例ID:" + task.getProcessInstanceId());
            //完成任务,这里测试请假3天触发一个角色多个审批人
            String jsonStr = JSONObject.toJSONString(activitiRequestDto.getReqeustBody());
            @SuppressWarnings("unchecked")
    		Map<String, Object> map = JSONObject.parseObject(jsonStr, Map.class);
            taskService.complete(task.getId(),map);
            //特别注意，获取ProcessDefinition是查看流程进度的关键
            ProcessDefinition processDefinition=repositoryService
            		.createProcessDefinitionQuery() // 创建流程定义查询
                    .processDefinitionId(task.getProcessDefinitionId()) // 根据流程定义id查询
                    .singleResult();
            //流程部署id
            String deploymentId = processDefinition.getDeploymentId(); 
            ActivitiResponseDto activitiResponseDto = new ActivitiResponseDto();
            activitiResponseDto.setTaskId(task.getId());
            activitiResponseDto.setTaskName(task.getName());
            activitiResponseDto.setTaskCreateDate(task.getCreateTime());
            activitiResponseDto.setAssignee(task.getAssignee());
            activitiResponseDto.setInstanceId(task.getProcessInstanceId());
            activitiResponseDto.setProcessDefinitionId(task.getProcessDefinitionId());
            //流程部署id
            activitiResponseDto.setDeploymentId(deploymentId);
            resultList.add(activitiResponseDto);
        }
        return resultList;
    }
    
    /**
     * 获取下一节点的所有审批人并且还有上一节点的审批意见。分两步：
     * 1、获取下一节点的所有审批人
     * 2、获取本节点
     * @param instanceId 流程实例id
     */
    public List<User> getNextUsers(String instanceId){
    	//1、获取下一节点的所有的用户
    	UserTask userTask = activeNoticeInfo.getNextUserFlowElement(instanceId);
    	List<String> groupsName = userTask.getCandidateGroups();
    	//获取到了最终的分组名称
    	String gourpName = groupsName.get(0);
    	List<User> nextUserList = userManage.getUserByGroupName(gourpName);
    	return nextUserList;
    }

    /**
     * 根据分组名称和processInstanceId获取Task，是用来获取taskid的，因为需要新的taskid来分配到人
     * @param groupName 分组的名称（）一般都是唯一的英文
     * @param instanceId 流程实例的id
     * @return
     */
    public List<ActivitiResponseDto> getTaskByGroupInstance(String groupName, String instanceId){
    	if(org.springframework.util.StringUtils.isEmpty(groupName)) {
    		groupName = null;
    	}
    	List<ActivitiResponseDto> taskList = new ArrayList<ActivitiResponseDto>();
        List<Task> list = taskService.createTaskQuery()
        		.taskCandidateGroup(groupName)
        		.processInstanceId(instanceId)
                .list();
        for (Task task : list) {
            System.out.println("--------------------------------------------");
            System.out.println("任务ID:" + task.getId());
            System.out.println("任务名称:" + task.getName());
            System.out.println("任务创建时间:" + task.getCreateTime());
            System.out.println("任务委派人:" + task.getAssignee());
            System.out.println("流程实例ID:" + task.getProcessInstanceId());
            ActivitiResponseDto activitiRes = new ActivitiResponseDto();
            activitiRes.setTaskId(task.getId());
            activitiRes.setTaskName(task.getName());
            activitiRes.setTaskCreateDate(task.getCreateTime());
            activitiRes.setAssignee(task.getAssignee());
            activitiRes.setProcessDefinitionId(task.getProcessInstanceId());
            taskList.add(activitiRes);
        }
        return taskList;
    }
    /**
     * 获取所有的审批人之后选择一个审批人，
     *并为该审批人拾取任务，这样才能提交任务
     *@param taskId
     *@param userId 页面传递过来的用户的id
     */
    public void claimTask(String taskId, String assignee){
        //拾取任务
        taskService.claim(taskId,assignee);
        //任务拾取以后, 可以回退给组
        //taskService.setAssignee(taskId, null);
        //任务拾取以后,可以转给别人去处理(别人可以是组成员也可以不是)
        //taskService.claim(taskId, "wangliu");
    }
    
    /**
     * 根据用户的账户查询该账户下所有的待办信息
     * @param assignee 账户
     * @param lastTaskId 上一个任务的id
     * @return
     */
    public List<ActivitiResponseDto> getTaskByUser(String assignee){
    	List<ActivitiResponseDto> resultList = new ArrayList<ActivitiResponseDto>();
    	List<Task> list = taskService.createTaskQuery()
    			.taskAssignee(assignee)
                .list();
        for (Task task : list) {
            System.out.println("--------------------------------------------");
            System.out.println("任务ID:" + task.getId());
            System.out.println("任务名称:" + task.getName());
            System.out.println("任务创建时间:" + task.getCreateTime());
            System.out.println("任务委派人:" + task.getAssignee());
            System.out.println("流程实例ID:" + task.getProcessInstanceId());
            ActivitiResponseDto activitiResponseDto = new ActivitiResponseDto();
            activitiResponseDto.setTaskId(task.getId());
            activitiResponseDto.setTaskName(task.getName());
            activitiResponseDto.setTaskCreateDate(task.getCreateTime());
            activitiResponseDto.setAssignee(task.getAssignee());
            activitiResponseDto.setAssignee(task.getAssignee());
            activitiResponseDto.setInstanceId(task.getProcessInstanceId());
            activitiResponseDto.setProcessDefinitionId(task.getProcessInstanceId());
            //获取开始申请时申请人传入的参数
            Object startParamObj = runtimeService.getVariable(task.getProcessInstanceId(), PublicKeyword.STARTPUBLICPARAM);
            String startParamStr = JSONObject.toJSONString(startParamObj);
            @SuppressWarnings("unchecked")
			Map<String, Object> startParamMap = JSONObject.parseObject(startParamStr, Map.class);
            activitiResponseDto.setParamMap(startParamMap);
            
            
            //获取上一审批节点并获取节点的审批意见
            Map<String, Object> opinionMap = taskService.getVariables(task.getId());
            Object opinionObj = opinionMap.get(PublicKeyword.OPINION);
            Object status = opinionMap.get(PublicKeyword.CHECKSTATUS);
            String opinion = "";
            if(opinionObj!=null) {
            	opinion = opinionObj.toString();
            }
            if(status!=null) {
            	activitiResponseDto.setCheckStatus(Integer.parseInt(status.toString()));
            }
            activitiResponseDto.setLastTaskId(task.getId());
            activitiResponseDto.setLastTaskOpinion(opinion);
            
            resultList.add(activitiResponseDto);
        }
        return resultList;
    }
    
    /**
     * 完成待办任务分为两步
     * 1、将审批意见放入到taskService中
     * 2、将任务审批完成
     * @param taskId 任务id
     * @param opinion 审批意见
     */
    public void taskComplateByTaskId(String taskId, String opinion) {
    	Map<String, String> map = new HashMap<String, String>();
    	map.put(PublicKeyword.OPINION, opinion);
    	map.put(PublicKeyword.CHECKSTATUS, InstanceStatus.PASS.getStatus().toString());
    	taskService.setVariables(taskId, map);
    	taskService.complete(taskId);
    }
}
